<?php

namespace controller;

// xml网站地图
if (preg_match('#/sitemap.xml$#', htmlentities($_SERVER['REQUEST_URI']))) {
    header('Content-type: text/xml; charset=UTF-8');
    header('HTTP/1.1 200 OK');
} else if (preg_match('#/api/#', $_SERVER['REQUEST_URI'])) {
    header('Content-type: application/json; charset=UTF-8');
    header('Access-Control-Allow-Origin: *');
    header('Access-Control-Allow-Methods: PUT, GET, POST, DELETE, OPTIONS');
} else {
    header('Content-type: text/html; charset=UTF-8');
}
define('IA_ROOT', str_replace('\\', DIRECTORY_SEPARATOR, __DIR__));

// 类自动加载器
require_once IA_ROOT . '/autoload.php';

class Mvc
{
    private static $_config;
    private static $_langs;
    private static $_modules;

    // 配置信息
    private function config()
    {
        if (self::$_config == null) {
            self::$_config = require IA_ROOT . '/config.php';
        }
    }

    // 语言
    private function langs()
    {
        if (self::$_langs == null) {
            self::$_langs = require IA_ROOT . '/mvc/locale/Lang.php';
        }
    }

    // 模块名称
    private function modules()
    {
        if (self::$_modules == null) {
            $_modules = [];
            foreach (glob(IA_ROOT . '/' . __NAMESPACE__ . '/*') as $_source) {
                if (is_dir($_source)) $_modules[] = basename($_source);
            }
            self::$_modules = $_modules;
        }
    }

    // 设置时区
    private function timezone()
    {
        date_default_timezone_set(isset(self::$_config['timezone']) ? self::$_config['timezone'] : 'Asia/Shanghai');
    }

    // Debug信息
    private function debug()
    {
        if (self::$_config['debug']) {
            error_reporting(E_ALL);
            ini_set('display_errors', '1');
            ini_set('error_log', IA_ROOT . '/error_log.txt');
        }
    }

    // 数据库零查询静态缓存
    private function cache()
    {
        $path_url = htmlentities($_SERVER['REQUEST_URI']);
        // 不缓存后台和api页面
        if (isset(self::$_config['cache']) && self::$_config['cache'] && !preg_match('#/admin/#', $path_url)) {
            $file_name = md5("http" . ((isset($_SERVER["HTTPS"]) && in_array(strtolower($_SERVER["HTTPS"]), ["on", "1"])) || (isset($_SERVER["SERVER_PORT"]) && "443" == $_SERVER["SERVER_PORT"]) ? "s" : "") . "://{$_SERVER["SERVER_NAME"]}" . (in_array($_SERVER["SERVER_PORT"], ["80", "443"]) ? "" : ":{$_SERVER['SERVER_PORT']}") . htmlentities($_SERVER['REQUEST_URI']));
            $cache_file = IA_ROOT . '/mvc/tpl/' . substr($file_name, 0, 2) . '/' . $file_name . '.php';
            // GET请求缓存，缓存前端GET请求页面
            if ($_SERVER['REQUEST_METHOD'] == 'GET') {
                // 如果缓存文件存在且没有过期
                if (file_exists($cache_file) && filesize($cache_file) > 1 && time() - filemtime($cache_file) < self::$_config['cache']) {
                    include $cache_file;
                    exit();
                }
                ob_start([$this, 'auto_cache']);
            } else {
                if (file_exists($cache_file)) {
                    unlink($cache_file);
                }
            }
        }
    }

    // 自动缓存
    private function auto_cache($contents)
    {
        // 不缓存404页面
        if (!preg_match('#<title>404[^<>]*not found</title>#', $contents)) {
            $file_name = md5("http" . ((isset($_SERVER["HTTPS"]) && in_array(strtolower($_SERVER["HTTPS"]), ["on", "1"])) || (isset($_SERVER["SERVER_PORT"]) && "443" == $_SERVER["SERVER_PORT"]) ? "s" : "") . "://{$_SERVER["SERVER_NAME"]}" . (in_array($_SERVER["SERVER_PORT"], ["80", "443"]) ? "" : ":{$_SERVER['SERVER_PORT']}") . htmlentities($_SERVER['REQUEST_URI']));
            // 根据md5前两位把缓存文件分散开，避免文件过多
            $cache_file = IA_ROOT . '/mvc/tpl/' . substr($file_name, 0, 2) . '/' . $file_name . '.php';
            $cache_path = dirname($cache_file);
            // 递归创建
            if (!is_dir($cache_path))
                mkdir($cache_path, 0700, true);
            file_put_contents($cache_file, "<?php defined('IA_ROOT') || exit(); ?>" . PHP_EOL);
            file_put_contents($cache_file, $contents, FILE_APPEND);
            chmod($cache_file, 0700);
            // 自动删除所有的老缓存，节约空间
            foreach (glob(IA_ROOT . '/mvc/tpl/*/*.php') as $file) {
                if (time() - filemtime($file) > self::$_config['cache']) {
                    unlink($file);
                }
            }
        }
        return $contents;
    }

    // 派发路由到控制器
    private function dispatch()
    {
        $pathInfo = parse_url(htmlentities($_SERVER['REQUEST_URI']), PHP_URL_PATH);
        // 多国语言
        $this->langs();
        $lang = strstr(ltrim($pathInfo, '/'), '/', true);
        if (array_filter(self::$_langs, function($item) use ($lang) {
            return $item['slug'] == $lang;
        }) && 0 === strpos(ltrim($pathInfo, '/'), $lang)) {
            $pathInfo = strstr(ltrim($pathInfo, '/'), '/');
        } else {
            $lang = 'zh-CN';
        }
        if (isset(self::$_config['route']) && self::$_config['route']) {
            // 强制路由模式
            $this->modules();
            $module = strstr(ltrim($pathInfo, '/'), '/', true);
            if (!in_array($module, self::$_modules)) $module = 'index';
            if (isset($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest')
                $requestMethod = 'ajax';
            else
                $requestMethod = strtolower($_SERVER['REQUEST_METHOD']);
            $routeDispatch = false;
            if (isset(self::$_config['rules'][$module][$requestMethod])) {
                foreach ((array)self::$_config['rules'][$module][$requestMethod] as $rule => $_controller) {
                    $matches = [];
                    if ($rule === $pathInfo || (substr_count($rule, '/') === substr_count($pathInfo, '/') && false !== strpos($rule, '(') && false !== strpos($rule, ')') && preg_match("#$rule#", $pathInfo, $matches))) {
                        $routeDispatch = true;
                        // 解析出路由参数
                        $params = array_slice($matches, 1);
                        // 解析出控制器
                        $controller = __NAMESPACE__ . '\\' . $module . '\\' . str_replace('/', '\\', dirname($_controller));
                        // 解析出方法
                        $method = basename($_controller);
                        // 传参调用控制器中的方法
                        call_user_func_array([new $controller(), $method], $params);
                        break;
                    }
                }
            }
            if (!$routeDispatch)
                include IA_ROOT . '/view/404.html';
        } else {
            // 非强制路由，分割 path info 并过滤空值数组
            $params = array_filter(explode('/', $pathInfo));
            // 解析出控制器
            $controller = __NAMESPACE__ . '\\' . ucfirst(preg_replace('/\.html/i', '', array_shift($params)) ?: 'Index') . 'Controller';
            // 解析出方法
            list($method,) = explode('.', array_shift($params));
            // 传参调用控制器中的方法
            if (is_file(str_replace('\\', '/', $controller) . '.php'))
                call_user_func_array([new $controller(), $method ?: 'Index'], $params);
            else
                include IA_ROOT . '/view/404.html';
        }
    }

    public function run()
    {
        $this->config();
        $this->timezone();
        $this->debug();
        $this->cache();
        $this->dispatch();
    }
}

(new Mvc())->run();
